using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Text;
using UnityEngine;

namespace ZerAx.TBON
{
    public abstract class TbonObject
    {
        public string Name { get; private set; }

        public TbonObject(string name)
        {
            Name = name;
        }

        public byte[] GetBytes()
        {
            using var stream = new MemoryStream();
            using var writer = new BinaryWriter(stream, Encoding.UTF8, false);
            Write(writer);
            return stream.ToArray();
        }

        public override string ToString() => $"<{Type}>{Name}:{GetValueString()}";

        public abstract TbonType Type { get; }
        public abstract void ReadValue(BinaryReader reader);
        public void Write(BinaryWriter writer)
        {
            writer.Write(Type.ToByte());
            writer.Write(Name);
            WriteValue(writer);
        }
        public abstract void WriteValue(BinaryWriter writer);
        public abstract string GetValueString();

        public static implicit operator byte[](TbonObject obj) => obj.GetBytes();

        protected static Dictionary<TbonType, Func<string, TbonObject>> factories = new();
        public static TbonObject Read(BinaryReader reader)
        {
            try
            {
                var type = reader.ReadByte().ToTbonType();
                var name = reader.ReadString();
                var nbt = factories[type](name);
                nbt.ReadValue(reader);
                return nbt;
            }
            catch (Exception)
            {
                return null;
            }
        }

        public static TbonObject FromBytes(byte[] bytes)
        {
            if (bytes == null || bytes.Length == 0) return null;
            using var reader = new BinaryReader(new MemoryStream(bytes), Encoding.UTF8, false);
            return Read(reader);
        }
    }
}
